This repository has no description
1import { createBobbinClient } from "$lib/api/client";
2import { languages as knotLanguages, tree as knotTree } from "$lib/api/knot";
3import { parallel } from "$lib/api/load";
4import {
5 branchesFor,
6 logFor,
7 sortTreeEntries,
8 tagsByCommitHash,
9 tagsFor,
10 toBranchSummary,
11 toCommitSummary,
12 toTagSummary,
13 toTreeEntrySummary
14} from "$lib/api/repo";
15import type { LanguageSlice } from "$lib/components/repo/types";
16import type { PageLoad } from "./$types";
17
18const COMMIT_LIMIT = 10;
19const BRANCH_LIMIT = 5;
20const TAG_LIMIT = 5;
21// knots cap ref listings at 100, so a total is really an "at least"
22const REF_LIMIT = 100;
23
24const orNull = <T>(promise: Promise<T>): Promise<T | null> => promise.catch(() => null);
25
26const toLanguageSlices = (languages: { name: string; size: number }[]): LanguageSlice[] => {
27 const sized = languages.filter((language) => language.size > 0);
28 const total = sized.reduce((sum, language) => sum + language.size, 0);
29 if (total === 0) return [];
30
31 const slices = sized.map((language) => {
32 const share = (language.size / total) * 100;
33 return { name: language.name, share, percentage: Math.floor(share) };
34 });
35
36 const short = 100 - slices.reduce((sum, slice) => sum + slice.percentage, 0);
37 [...slices]
38 .sort((a, b) => (b.share % 1) - (a.share % 1) || b.share - a.share)
39 .slice(0, Math.max(0, short))
40 .forEach((slice) => {
41 slice.percentage += 1;
42 });
43
44 return slices.sort((a, b) => b.share - a.share);
45};
46
47export const load: PageLoad = async (event) => {
48 const parent = await event.parent();
49 const ctx = createBobbinClient({ serviceUrl: parent.publicConfig.bobbinUrl, fetch: event.fetch });
50 const repo = parent.repo.uri;
51 const ref = parent.repo.defaultBranch;
52
53 // every list falls back on its own so a partial page still renders
54 const results = await parallel({
55 tree: orNull(knotTree(ctx, { repo, ref })),
56 log: orNull(logFor(ctx, repo, ref, COMMIT_LIMIT)),
57 branches: orNull(branchesFor(ctx, repo, REF_LIMIT)),
58 tags: orNull(tagsFor(ctx, repo, REF_LIMIT)),
59 languages: orNull(knotLanguages(ctx, { repo, ref }))
60 });
61
62 const branches = (results.branches?.branches ?? []).map(toBranchSummary);
63 const tags = (results.tags?.tags ?? []).map(toTagSummary);
64 const commits = (results.log?.commits ?? []).map(toCommitSummary);
65 const files = sortTreeEntries((results.tree?.files ?? []).map(toTreeEntrySummary));
66
67 const languages = toLanguageSlices(results.languages?.languages ?? []);
68
69 // nothing answered, so the knot is down or doesn't know this repo
70 const knotUnreachable =
71 results.tree === null && results.log === null && results.branches === null;
72 // the knot answered but there is nothing there, so it was never pushed to
73 const isEmpty = !knotUnreachable && files.length === 0 && branches.length === 0;
74
75 return {
76 ref,
77 isEmpty,
78 knotUnreachable,
79 files,
80 readme: results.tree?.readme ?? null,
81 commits,
82 tagsByCommit: tagsByCommitHash(commits, tags),
83 totalCommits: results.log?.total ?? commits.length,
84 branches: branches.slice(0, BRANCH_LIMIT),
85 totalBranches: branches.length,
86 tags: tags.slice(0, TAG_LIMIT),
87 totalTags: tags.length,
88 // the switcher needs every ref, not just the visible slice
89 refs: {
90 branches: branches.map((branch) => branch.name),
91 tags: tags.map((tag) => tag.name),
92 capped: branches.length >= REF_LIMIT || tags.length >= REF_LIMIT
93 },
94 languages
95 };
96};